package singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//懒汉式
public class LazyMan {
    private static boolean xiaoyu = false;
    private LazyMan(){
        //解决办法
//        synchronized (LazyMan.class){
//            if (lazyMan!=null){
//                throw new RuntimeException("不用试图用反射破坏构造器！！");
//            }
//        }
        //都用反射创建实例的情况
        synchronized (LazyMan.class) {
            if (xiaoyu==false){
                xiaoyu=true;
            }else {
                throw new RuntimeException("不用试图用反射破坏构造器！！");
            }
        }
    }
    private static LazyMan lazyMan = null;
    public static LazyMan getInstance(){
        //只创建一次实例，如果第一次不判断，每次线程进来都要进行判断，大大降低性能
        //第一次创建实例后，其他线程直接返回对象，不走同步代码块的代码
        if (lazyMan==null){
            //第二次判断 AB两个线程,A挂起，B创建实例，A获得所再次创建实例，违背了单例的初衷
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    //这里可能会发生指令重排现象，要加上voliatile
                    //1.分配内存空间  2.初始化对象  3.指向内存空间 132指令重排 lazyman!=null
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }
    //反射可以破坏单例模式
    public static void main(String[] args) throws Exception {

//        LazyMan instance1= LazyMan.getInstance();
//        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor();
//        //启用安全检查，破坏单例模式(主要是破坏的构造器，解决办法从构造器入手)
//        constructor.setAccessible(true);
//        LazyMan instance2 = constructor.newInstance();
//        System.out.println(instance2);
//        System.out.println(instance1);

        //都用反射创造对象的情况
//        LazyMan instance1 = LazyMan.getInstance();
        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor();
        //启用安全检查，破坏单例模式(主要是破坏的构造器，解决办法从构造器入手)
        constructor.setAccessible(true);
        LazyMan instance1 = constructor.newInstance();
        LazyMan instance2 = constructor.newInstance();
        System.out.println(instance1);
        System.out.println(instance2);

    }
}
